/* picoc expression evaluator - a stack-based expression evaluation system
 * which handles operator precedence */
#include "expression.h"
#include "variable.h"
#include "lex.h"
#include "table.h"
#include "platform.h"
#include "type.h"
#include "parse.h"
/* whether evaluation is left to right for a given precedence level */
#define IS_LEFT_TO_RIGHT(p) ((p) != 2 && (p) != 14)
#define BRACKET_PRECEDENCE (20)

/* If the destination is not float, we can't assign a floating Value to it,
    we need to convert it to integer instead */
#define ASSIGN_FP_OR_INT(value) \
        if (IS_FP(bottomValue)) { \
            resultFP = ExpressionAssignFP(parser, bottomValue, value); \
        } else { \
            resultInt = ExpressionAssignInt(parser, bottomValue,  (long)(value), false); \
            resultIsInt = true; }

#define DEEP_PRECEDENCE (BRACKET_PRECEDENCE*1000)



/* NOTE: the order of this array must correspond exactly to the order of
    these tokens in LexToken */
const Expression::OpPrecedence Expression::operatorPrecedence[] = {
    /* kTokenNone, */ {0, 0, 0, "none"},
    /* kTokenComma, */ {0, 0, 0, ","},
    /* kTokenAssign, */ {0, 0, 2, "="},
    /* kTokenAddAssign, */ {0, 0, 2, "+="},
    /* kTokenSubtractAssign, */ {0, 0, 2, "-="},
    /* kTokenMultiplyAssign, */ {0, 0, 2, "*="},
    /* kTokenDivideAssign, */ { 0, 0, 2, "/=" },
    /* kTokenModulusAssign, */ { 0, 0, 2, "%=" },
    /* kTokenShiftLeftAssign, */ {0, 0, 2, "<<="},
    /* kTokenShiftRightAssign, */ { 0, 0, 2, ">>=" },
    /* kTokenArithmeticAndAssign, */ { 0, 0, 2, "&=" },
    /* kTokenArithmeticOrAssign, */ {0, 0, 2, "|="},
    /* kTokenArithmeticExorAssign, */ { 0, 0, 2, "^=" },
    /* kTokenQuestionMark, */ {0, 0, 3, "?"},
    /* kTokenColon, */ {0, 0, 3, ":" },
    /* kTokenLogicalOr, */ {0, 0, 4, "||"},
    /* kTokenLogicalAnd, */ {0, 0, 5, "&&"},
    /* kTokenArithmeticOr, */ {0, 0, 6, "|"},
    /* kTokenArithmeticExor, */ {0, 0, 7, "^"},
    /* kTokenAmpersand, */ {14, 0, 8, "&"},
    /* kTokenEqual, */  {0, 0, 9, "=="},
    /* kTokenNotEqual, */ {0, 0, 9, "!="},
    /* kTokenLessThan, */ {0, 0, 10, "<"},
    /* kTokenGreaterThan, */ {0, 0, 10, ">"},
    /* kTokenLessEqual, */ {0, 0, 10, "<="},
    /* kTokenGreaterEqual, */ {0, 0, 10, ">="},
    /* kTokenShiftLeft, */ {0, 0, 11, "<<"},
    /* kTokenShiftRight, */ {0, 0, 11, ">>"},
    /* kTokenPlus, */ {14, 0, 12, "+"},
    /* kTokenMinus, */ {14, 0, 12, "-"},
    /* kTokenAsterisk, */ {14, 0, 13, "*"},
    /* kTokenSlash, */ {0, 0, 13, "/"},
    /* kTokenModulus, */ {0, 0, 13, "%"},
    /* kTokenIncrement, */ {14, 15, 0, "++"},
    /* kTokenDecrement, */ {14, 15, 0, "--"},
    /* kTokenUnaryNot, */ {14, 0, 0, "!"},
    /* kTokenUnaryExor, */ {14, 0, 0, "~"},
    /* kTokenSizeof, */ {14, 0, 0, "sizeof"},
    /* kTokenCast, */ {14, 0, 0, "cast"},
    /* kTokenLeftSquareBracket, */ {0, 0, 15, "["},
    /* kTokenRightSquareBracket, */ {0, 15, 0, "]"},
    /* kTokenDot, */ {0, 0, 15, "."},
    /* kTokenArrow, */ {0, 0, 15, "->"},
    /* kTokenOpenBracket, */ {15, 0, 0, "("},
    /* kTokenCloseBracket, */ {0, 15, 0, ")"}
};



#ifdef DEBUG_EXPRESSIONS
/* show the contents of the expression stack */
void Expression::ExpressionStackShow(Interpreter *pc, ExpressionStack *stackTop) {
    printf("Expression stack [0x%lx,0x%lx]: ", (long)pc->heapStackTop, (long)stackTop);

    while (stackTop != NULL) {
        if (stackTop->order == kOrderNone) {
            /* it's a Value */
            if (stackTop->val->isLValue)
                printf("lvalue=");
            else
                printf("Value=");

            switch (stackTop->val->typ->base) {
            case kTypeVoid:
                printf("void");
                break;
            case kTypeInt:
                printf("%d:int", stackTop->val->val->integer);
                break;
            case kTypeShort:
                printf("%d:short", stackTop->val->val->shortInteger);
                break;
            case kTypeChar:
                printf("%d:char", stackTop->val->val->character);
                break;
            case kTypeLong:
                printf("%ld:long", stackTop->val->val->longInteger);
                break;
            case kTypeUnsignedShort:
                printf("%d:unsigned short", stackTop->val->val->unsignedShortInteger);
                break;
            case kTypeUnsignedInt:
                printf("%d:unsigned int", stackTop->val->val->unsignedInteger);
                break;
            case kTypeUnsignedLong:
                printf("%ld:unsigned long", stackTop->val->val->unsignedLongInteger);
                break;
            case kTypeFP:
                printf("%f:fp", stackTop->val->val->fP);
                break;
            case kTypeFunction:
                printf("%s:function", stackTop->val->val->identifier);
                break;
            case kTypeMacro:
                printf("%s:macro", stackTop->val->val->identifier);
                break;
            case kTypePointer:
                if (stackTop->val->val->pointer == NULL)
                    printf("ptr(NULL)");
                else if (stackTop->val->typ->fromType->base == kTypeChar)
                    printf("\"%s\":string", (char *)stackTop->val->val->pointer);
                else
                    printf("ptr(0x%lx)", (long)stackTop->val->val->pointer);
                break;
            case kTypeArray:
                printf("array");
                break;
            case kTypeStruct:
                printf("%s:struct", stackTop->val->val->identifier);
                break;
            case kTypeUnion:
                printf("%s:union", stackTop->val->val->identifier);
                break;
            case kTypeEnum:
                printf("%s:enum", stackTop->val->val->identifier);
                break;
            case kTypeType:
                PrintType(stackTop->val->val->typ, pc->cStdOut);
                printf(":type");
                break;
            default:
                printf("unknown");
                break;
            }
            printf("[0x%lx,0x%lx]", (long)stackTop, (long)stackTop->val);
        } else {
            /* it's an operator */
            printf("op='%s' %s %d", operatorPrecedence[(int)stackTop->op].name,
                (stackTop->order == kOrderPrefix) ?
                    "prefix" : ((stackTop->order == kOrderPostfix) ? "postfix" : "infix"),
                stackTop->precedence);
            printf("[0x%lx]", (long)stackTop);
        }

        stackTop = stackTop->next;
        if (stackTop != NULL)
            printf(", ");
    }

    printf("\n");
}
#endif

int Expression::IsTypeToken(ParseState *parser, LexToken t,
    Value * lexValue) {
    if (t >= kTokenIntType && t <= kTokenUnsignedType)
        return 1; /* base type */

    /* typedef'ed type? */
    if (t == kTokenIdentifier) {
        /* see TypeParseFront, case kTokenIdentifier and ParseTypedef */
        Value * varValue = NULL;
        if ((parser->pc, (const char *)lexValue->val->pointer)) {
            (parser->pc, parser, (const char *)lexValue->val->pointer, &varValue);
            if (varValue->typ == &parser->pc->typeType)
                return 1;
        }
    }

    return 0;
}

long Expression::ExpressionCoerceInteger(Value *val) {
    switch (val->typ->base) {
    case kTypeInt:
        return (long)val->val->integer;
    case kTypeChar:
        return (long)val->val->character;
    case kTypeShort:
        return (long)val->val->shortInteger;
    case kTypeLong:
        return (long)val->val->longInteger;
    case kTypeUnsignedInt:
        return (long)val->val->unsignedInteger;
    case kTypeUnsignedShort:
        return (long)val->val->unsignedShortInteger;
    case kTypeUnsignedLong:
        return (long)val->val->unsignedLongInteger;
    case kTypeUnsignedChar:
        return (long)val->val->unsignedCharacter;
    case kTypePointer:
        return (long)val->val->pointer;
    case kTypeFP:
        return (long)val->val->fP;
    default:
        return 0;
    }
}

unsigned long Expression::ExpressionCoerceUnsignedInteger(Value *val) {
    switch (val->typ->base) {
    case kTypeInt:
        return (unsigned long)val->val->integer;
    case kTypeChar:
        return (unsigned long)val->val->character;
    case kTypeShort:
        return (unsigned long)val->val->shortInteger;
    case kTypeLong:
        return (unsigned long)val->val->longInteger;
    case kTypeUnsignedInt:
        return (unsigned long)val->val->unsignedInteger;
    case kTypeUnsignedShort:
        return (unsigned long)val->val->unsignedShortInteger;
    case kTypeUnsignedLong:
        return (unsigned long)val->val->unsignedLongInteger;
    case kTypeUnsignedChar:
        return (unsigned long)val->val->unsignedCharacter;
    case kTypePointer:
        return (unsigned long)val->val->pointer;
    case kTypeFP:
        return (unsigned long)val->val->fP;
    default:
        return 0;
    }
}

double Expression::ExpressionCoerceFP(Value *val) {
    switch (val->typ->base) {
    case kTypeInt:
        return (double)val->val->integer;
    case kTypeChar:
        return (double)val->val->character;
    case kTypeShort:
        return (double)val->val->shortInteger;
    case kTypeLong:
        return (double)val->val->longInteger;
    case kTypeUnsignedInt:
        return (double)val->val->unsignedInteger;
    case kTypeUnsignedShort:
        return (double)val->val->unsignedShortInteger;
    case kTypeUnsignedLong:
        return (double)val->val->unsignedLongInteger;
    case kTypeUnsignedChar:
        return (double)val->val->unsignedCharacter;
    case kTypeFP:
        return val->val->fP;
    default:
        return 0.0;
    }
}

/* assign an integer Value */
long Expression::ExpressionAssignInt(ParseState *parser, Value *destValue,
    long fromInt, int after) {
    long result;

    if (!destValue->isLValue)
        Platform::ProgramFail(parser, "can't assign to this");

    if (after)
        result = ExpressionCoerceInteger(destValue);
    else
        result = fromInt;

    switch (destValue->typ->base) {
    case kTypeInt:
        destValue->val->integer = (int)fromInt;
        break;
    case kTypeShort:
        destValue->val->shortInteger = (short)fromInt;
        break;
    case kTypeChar:
        destValue->val->character = (char)fromInt;
        break;
    case kTypeLong:
        destValue->val->longInteger = (long)fromInt;
        break;
    case kTypeUnsignedInt:
        destValue->val->unsignedInteger = (unsigned int)fromInt;
        break;
    case kTypeUnsignedShort:
        destValue->val->unsignedShortInteger = (unsigned short)fromInt;
        break;
    case kTypeUnsignedLong:
        destValue->val->unsignedLongInteger = (unsigned long)fromInt;
        break;
    case kTypeUnsignedChar:
        destValue->val->unsignedCharacter = (unsigned char)fromInt;
        break;
    default:
        break;
    }
    return result;
}

/* assign a floating point Value */
double Expression::ExpressionAssignFP(ParseState *parser, Value *destValue,
    double fromFP) {
    if (!destValue->isLValue)
        Platform::ProgramFail(parser, "can't assign to this");

    destValue->val->fP = fromFP;
    return fromFP;
}

/* push a node on to the expression stack */
void Expression::ExpressionStackPushValueNode(ParseState *parser,
    ExpressionStack **stackTop, Value *valueLoc) {
    ExpressionStack *stackNode = (ExpressionStack *)(parser->pc, parser,
                                        sizeof(*stackNode), false);
    stackNode->next = *stackTop;
    stackNode->val = valueLoc;
    *stackTop = stackNode;
#ifdef FANCY_ERROR_MESSAGES
    stackNode->line = parser->line;
    stackNode->characterPos = parser->characterPos;
#endif
#ifdef DEBUG_EXPRESSIONS
    ExpressionStackShow(parser->pc, *stackTop);
#endif
}

/* push a blank Value on to the expression stack by type */
Value *Expression::ExpressionStackPushValueByType(ParseState *parser,
    ExpressionStack **stackTop, ValueType *pushType) {
    Value *valueLoc = (parser->pc, parser,
            pushType, false, NULL, false);
    ExpressionStackPushValueNode(parser, stackTop, valueLoc);

    return valueLoc;
}

/* push a Value on to the expression stack */
void Expression::ExpressionStackPushValue(ParseState *parser,
    ExpressionStack **stackTop, Value *pushValue) {
    Value *valueLoc = (parser->pc, parser,
        pushValue, false);
    ExpressionStackPushValueNode(parser, stackTop, valueLoc);
}

void Expression::ExpressionStackPushLValue(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, Value *pushValue, int offset) {
    Value *valueLoc = Variable::VariableAllocValueShared(pc, parser, pushValue);
    valueLoc->val = (AnyValue *)(void *)((char *)valueLoc->val + offset);
    ExpressionStackPushValueNode(parser, stackTop, valueLoc);
}

void Expression::ExpressionStackPushDereference(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, Value *dereferenceValue) {
    int offset;
    int derefIsLValue;
    Value *derefVal;
    Value *valueLoc;
    ValueType *DerefType;
    void *derefDataLoc = Variable::VariableDereferencePointer(dereferenceValue, &derefVal,
        &offset, &DerefType, &derefIsLValue);
    if (derefDataLoc == NULL)
        Platform::ProgramFail(parser, "NULL pointer dereference");

    valueLoc = Variable::VariableAllocValueFromExistingData(pc, parser, DerefType,
                    (AnyValue*)derefDataLoc, derefIsLValue, derefVal);
    ExpressionStackPushValueNode(parser, stackTop, valueLoc);
}

void Expression::ExpressionPushInt(ParseState *parser,
            ExpressionStack **stackTop, long intValue) {
    Value *valueLoc = (parser->pc, parser,
                            &parser->pc->intType, false, NULL, false);
    // jdp: an ugly hack to a) assign the correct Value and b) properly print long values
    valueLoc->val->unsignedLongInteger = (unsigned long)intValue;
    valueLoc->val->longInteger = (long)intValue;
    valueLoc->val->integer = (int)intValue;
    valueLoc->val->shortInteger = (short)intValue;
    valueLoc->val->unsignedShortInteger = (unsigned short)intValue;
    valueLoc->val->unsignedInteger = (unsigned int)intValue;
    valueLoc->val->unsignedCharacter = (unsigned char)intValue;
    valueLoc->val->character = (char)intValue;

    ExpressionStackPushValueNode(parser, stackTop, valueLoc);
}

void Expression::ExpressionPushFP(ParseState *parser,
    ExpressionStack **stackTop, double fPValue) {
    Value *valueLoc = (parser->pc, parser,
                                 &parser->pc->fPType, false, NULL, false);
    valueLoc->val->fP = fPValue;
    ExpressionStackPushValueNode(parser, stackTop, valueLoc);
}

/* assign to a pointer */
void Expression::ExpressionAssignToPointer(ParseState *parser, Value *toValue,
    Value *fromValue, const char *funcName, int paramNo,
    int allowPointerCoercion) {
    ValueType *pointedToType = toValue->typ->fromType;

    if (fromValue->typ == toValue->typ ||
            fromValue->typ == parser->pc->voidPtrType ||
            (toValue->typ == parser->pc->voidPtrType &&
            fromValue->typ->base == kTypePointer))
        toValue->val->pointer = fromValue->val->pointer; /* plain old pointer assignment */
    else if (fromValue->typ->base == kTypeArray &&
            (pointedToType == fromValue->typ->fromType ||
            toValue->typ == parser->pc->voidPtrType)) {
        /* the form is: blah *x = array of blah */
        toValue->val->pointer = (void *)&fromValue->val->arrayMem[0];
    } else if (fromValue->typ->base == kTypePointer &&
                fromValue->typ->fromType->base == kTypeArray &&
               (pointedToType == fromValue->typ->fromType->fromType ||
                toValue->typ == parser->pc->voidPtrType) ) {
        /* the form is: blah *x = pointer to array of blah */
        toValue->val->pointer = Variable::VariableDereferencePointer(fromValue, NULL,
            NULL, NULL, NULL);
    } else if (IS_NUMERIC_COERCIBLE(fromValue) &&
            ExpressionCoerceInteger(fromValue) == 0) {
        /* null pointer assignment */
        toValue->val->pointer = NULL;
    } else if (allowPointerCoercion && IS_NUMERIC_COERCIBLE(fromValue)) {
        /* assign integer to native pointer */
        toValue->val->pointer =
            (void*)(unsigned long)ExpressionCoerceUnsignedInteger(fromValue);
    } else if (allowPointerCoercion && fromValue->typ->base == kTypePointer) {
        /* assign a pointer to a pointer to a different type */
        toValue->val->pointer = fromValue->val->pointer;
    } else
        Platform::AssignFail(parser, "%t from %t", toValue->typ, fromValue->typ, 0, 0,
            funcName, paramNo);
}

/* assign any kind of Value */
void Expression::ExpressionAssign(Interpreter *pc, ParseState *parser, Value *destValue,
    Value *sourceValue, int force, const char *funcName, int paramNo,
    int allowPointerCoercion) {
    if (!destValue->isLValue && !force)
        Platform::AssignFail(parser, "not an lvalue", NULL, NULL, 0, 0, funcName, paramNo);

    if (IS_NUMERIC_COERCIBLE(destValue) &&
            !IS_NUMERIC_COERCIBLE_PLUS_POINTERS(sourceValue, allowPointerCoercion))
        Platform::AssignFail(parser, "%t from %t", destValue->typ, sourceValue->typ, 0, 0,
            funcName, paramNo);

    switch (destValue->typ->base) {
    case kTypeInt:
        destValue->val->integer = (int)ExpressionCoerceInteger(sourceValue);
        break;
    case kTypeShort:
        destValue->val->shortInteger = (short)ExpressionCoerceInteger(sourceValue);
        break;
    case kTypeChar:
        destValue->val->character = (char)ExpressionCoerceInteger(sourceValue);
        break;
    case kTypeLong:
        destValue->val->longInteger = sourceValue->val->longInteger;
        break;
    case kTypeUnsignedInt:
        destValue->val->unsignedInteger =
            (unsigned int)ExpressionCoerceUnsignedInteger(sourceValue);
        break;
    case kTypeUnsignedShort:
        destValue->val->unsignedShortInteger =
            (unsigned short)ExpressionCoerceUnsignedInteger(sourceValue);
        break;
    case kTypeUnsignedLong:
        destValue->val->unsignedLongInteger = sourceValue->val->unsignedLongInteger;
        break;
    case kTypeUnsignedChar:
        destValue->val->unsignedCharacter =
            (unsigned char)ExpressionCoerceUnsignedInteger(sourceValue);
        break;
    case kTypeFP:
        if (!IS_NUMERIC_COERCIBLE_PLUS_POINTERS(sourceValue, allowPointerCoercion))
            Platform::AssignFail(parser, "%t from %t", destValue->typ, sourceValue->typ,
                0, 0, funcName, paramNo);
        destValue->val->fP = (double)ExpressionCoerceFP(sourceValue);
        break;
    case kTypePointer:
        ExpressionAssignToPointer(parser, destValue, sourceValue, funcName,
            paramNo, allowPointerCoercion);
        break;
    case kTypeArray:
        if (sourceValue->typ->base == kTypeArray && destValue->typ->arraySize == 0) {
            /* destination array is unsized - need to resize the destination
                array to the same size as the source array */
            destValue->typ = sourceValue->typ;
            Variable::VariableRealloc(pc, parser, destValue, Type::TypeSizeValue(destValue, false));

            if (destValue->lValueFrom != NULL) {
                /* copy the resized Value back to the LValue */
                destValue->lValueFrom->val = destValue->val;
                destValue->lValueFrom->anyValOnHeap = destValue->anyValOnHeap;
            }
        }
        /* char array = "abcd" */
        if (destValue->typ->fromType->base == kTypeChar &&
                sourceValue->typ->base == kTypePointer &&
                sourceValue->typ->fromType->base == kTypeChar) {
            if (destValue->typ->arraySize == 0) { /* char x[] = "abcd", x is unsized */
                int size = strlen((const char *)sourceValue->val->pointer) + 1;
#ifdef DEBUG_ARRAY_INITIALIZER
                PRINT_SOURCE_POS();
                fprintf(stderr, "str size: %d\n", size);
#endif
                destValue->typ = Type::TypeGetMatching(parser->pc, parser,
                            destValue->typ->fromType, destValue->typ->base,
                            size, destValue->typ->identifier, true);
                Variable::VariableRealloc(pc, parser, destValue, Type::TypeSizeValue(destValue,
                    false));
            }
            /* else, it's char x[10] = "abcd" */

#ifdef DEBUG_ARRAY_INITIALIZER
            PRINT_SOURCE_POS();
            fprintf(stderr, "char[%d] from char* (len=%d)\n",
                    destValue->typ->arraySize,
                    strlen(sourceValue->val->pointer));
#endif
            memcpy((void*)destValue->val, sourceValue->val->pointer,
                Type::TypeSizeValue(destValue, false));
            break;
        }

        if (destValue->typ != sourceValue->typ)
            Platform::AssignFail(parser, "%t from %t", destValue->typ, sourceValue->typ,
                0, 0, funcName, paramNo);

        if (destValue->typ->arraySize != sourceValue->typ->arraySize)
            Platform::AssignFail(parser, "from an array of size %d to one of size %d",
                NULL, NULL, destValue->typ->arraySize,
                sourceValue->typ->arraySize, funcName, paramNo);

        memcpy((void*)destValue->val, (void*)sourceValue->val,
                Type::TypeSizeValue(destValue, false));
        break;
    case kTypeStruct:
    case kTypeUnion:
        if (destValue->typ != sourceValue->typ)
            Platform::AssignFail(parser, "%t from %t", destValue->typ, sourceValue->typ,
                        0, 0, funcName, paramNo);
        memcpy((void*)destValue->val, (void*)sourceValue->val,
                Type::TypeSizeValue(sourceValue, false));
        break;
    default:
        Platform::AssignFail(parser, "%t", destValue->typ, NULL, 0, 0, funcName, paramNo);
        break;
    }
}

/* evaluate the first half of a ternary operator x ? y : z */
void Expression::ExpressionQuestionMarkOperator(ParseState *parser,
    ExpressionStack **stackTop, Value *bottomValue,
    Value *topValue) {
    if (!IS_NUMERIC_COERCIBLE(topValue))
        Platform::ProgramFail(parser, "first argument to '?' should be a number");

    if (ExpressionCoerceInteger(topValue)) {
        /* the condition's true, return the bottomValue */
        ExpressionStackPushValue(parser, stackTop, bottomValue);
    } else {
        /* the condition's false, return void */
        ExpressionStackPushValueByType(parser, stackTop, &parser->pc->voidType);
    }
}

/* evaluate the second half of a ternary operator x ? y : z */
void Expression::ExpressionColonOperator(ParseState *parser,
    ExpressionStack **stackTop, Value *bottomValue,
    Value *topValue) {
    if (topValue->typ->base == kTypeVoid) {
        /* invoke the "else" part - return the bottomValue */
        ExpressionStackPushValue(parser, stackTop, bottomValue);
    } else {
        /* it was a "then" - return the topValue */
        ExpressionStackPushValue(parser, stackTop, topValue);
    }
}

/* evaluate a prefix operator */
void Expression::ExpressionPrefixOperator(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, LexToken op, Value *topValue) {
    Value *result;
    AnyValue *valPtr;
    ValueType *typ;

#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionPrefixOperator()\n");
#endif

    switch (op) {
    case kTokenAmpersand:
        if (!topValue->isLValue)
            Platform::ProgramFail(parser, "can't get the address of this");

        valPtr = topValue->val;
        result = (parser->pc, parser,
                    Type::TypeGetMatching(parser->pc, parser, topValue->typ,
                        kTypePointer, 0, parser->pc->strEmpty, true),
                    false, NULL, false);
        result->val->pointer = (void*)valPtr;
        ExpressionStackPushValueNode(parser, stackTop, result);
        break;
    case kTokenAsterisk:
        if(stackTop != NULL && (*stackTop) != NULL && (*stackTop)->op == kTokenSizeof)
            /* ignored */
            ExpressionStackPushValueByType(parser, stackTop, topValue->typ);
        else
            ExpressionStackPushDereference(pc, parser, stackTop, topValue);
        break;
    case kTokenSizeof:
        /* return the size of the argument */
        if (topValue->typ == &parser->pc->typeType)
            typ = topValue->val->typ;
        else
            typ = topValue->typ;
        if (typ->fromType != NULL && typ->fromType->base == kTypeStruct)
            typ = typ->fromType;
        ExpressionPushInt(parser, stackTop, Type::TypeSize(typ, typ->arraySize, true));
        break;
    default:
        /* an arithmetic operator */
        if (topValue->typ == &parser->pc->fPType) {
            /* floating point prefix arithmetic */
            double resultFP = 0.0;
            switch (op) {
            case kTokenPlus:
                resultFP = topValue->val->fP;
                break;
            case kTokenMinus:
                resultFP = -topValue->val->fP;
                break;
            case kTokenIncrement:
                resultFP = ExpressionAssignFP(parser, topValue,
                    topValue->val->fP+1);
                break;
            case kTokenDecrement:
                resultFP = ExpressionAssignFP(parser, topValue,
                    topValue->val->fP-1);
                break;
            case kTokenUnaryNot:
                resultFP = !topValue->val->fP;
                break;
            default:
                Platform::ProgramFail(parser, "invalid operation");
                break;
            }
            ExpressionPushFP(parser, stackTop, resultFP);
        } else if (IS_NUMERIC_COERCIBLE(topValue)) {
            /* integer prefix arithmetic */
            long resultInt = 0;
            long topInt = 0;
            if (topValue->typ->base == kTypeLong)
                topInt = topValue->val->longInteger;
            else
                topInt = ExpressionCoerceInteger(topValue);
            switch (op) {
            case kTokenPlus:
                resultInt = topInt;
                break;
            case kTokenMinus:
                resultInt = -topInt;
                break;
            case kTokenIncrement:
                resultInt = ExpressionAssignInt(parser, topValue,
                    topInt+1, false);
                break;
            case kTokenDecrement:
                resultInt = ExpressionAssignInt(parser, topValue,
                    topInt-1, false);
                break;
            case kTokenUnaryNot:
                resultInt = !topInt;
                break;
            case kTokenUnaryExor:
                resultInt = ~topInt;
                break;
            default:
                Platform::ProgramFail(parser, "invalid operation");
                break;
            }
            ExpressionPushInt(parser, stackTop, resultInt);
        } else if (topValue->typ->base == kTypePointer) {
            /* pointer prefix arithmetic */
            int size = Type::TypeSize(topValue->typ->fromType, 0, true);
            Value *stackValue;
            void *ResultPtr = 0;
            if (op != kTokenUnaryNot && topValue->val->pointer == NULL)
                Platform::ProgramFail(parser, "a. invalid use of a NULL pointer");
            if (!topValue->isLValue)
                Platform::ProgramFail(parser, "can't assign to this");
            switch (op) {
            case kTokenIncrement:
                ResultPtr = topValue->val->pointer =
                    (void*)((char*)topValue->val->pointer+size);
                break;
            case kTokenDecrement:
                ResultPtr = topValue->val->pointer =
                    (void*)((char*)topValue->val->pointer-size);
                break;
            case kTokenUnaryNot:
                /* conditionally checking a pointer's Value, we only want
                    to change the stack Value (ResultPtr) and not the pointer's
                    actual Value  */
                topValue->val->pointer =
                    (void*)((char*)topValue->val->pointer);
                    ResultPtr = topValue->val->pointer ? NULL : (void*)0x01;
                break;
            default:
                Platform::ProgramFail(parser, "invalid operation");
                break;
            }
            stackValue = ExpressionStackPushValueByType(parser, stackTop,
                topValue->typ);
            stackValue->val->pointer = ResultPtr;
        } else {
            Platform::ProgramFail(parser, "invalid operation");
        }
        break;
    }
}

/* evaluate a postfix operator */
void Expression::ExpressionPostfixOperator(ParseState *parser,
    ExpressionStack **stackTop, LexToken op, Value *topValue) {
#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionPostfixOperator()\n");
#endif

    if (topValue->typ == &parser->pc->fPType) {
        /* floating point prefix arithmetic */
        double resultFP = 0.0;

        switch (op) {
        case kTokenIncrement:
            resultFP = ExpressionAssignFP(parser, topValue, topValue->val->fP+1);
            break;
        case kTokenDecrement:
            resultFP = ExpressionAssignFP(parser, topValue, topValue->val->fP-1);
            break;
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }
        ExpressionPushFP(parser, stackTop, resultFP);
    } else if (IS_NUMERIC_COERCIBLE(topValue)) {
        long resultInt = 0;
        long topInt = ExpressionCoerceInteger(topValue);
        switch (op) {
        case kTokenIncrement:
            resultInt = ExpressionAssignInt(parser, topValue, topInt+1, true);
            break;
        case kTokenDecrement:
            resultInt = ExpressionAssignInt(parser, topValue, topInt-1, true);
            break;
        case kTokenRightSquareBracket:
            Platform::ProgramFail(parser, "not supported");
            break;  /* XXX */
        case kTokenCloseBracket:
            Platform::ProgramFail(parser, "not supported");
            break;  /* XXX */
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }
        ExpressionPushInt(parser, stackTop, resultInt);
    } else if (topValue->typ->base == kTypePointer) {
        /* pointer postfix arithmetic */
        int size = Type::TypeSize(topValue->typ->fromType, 0, true);
        Value *stackValue;
        void *OrigPointer = topValue->val->pointer;

        if (topValue->val->pointer == NULL)
            Platform::ProgramFail(parser, "b. invalid use of a NULL pointer");

        if (!topValue->isLValue)
            Platform::ProgramFail(parser, "can't assign to this");

        switch (op) {
        case kTokenIncrement:
            topValue->val->pointer = (void*)((char*)topValue->val->pointer+size);
            break;
        case kTokenDecrement:
            topValue->val->pointer = (void*)((char*)topValue->val->pointer-size);
            break;
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }
        stackValue = ExpressionStackPushValueByType(parser, stackTop,
            topValue->typ);
        stackValue->val->pointer = OrigPointer;
    } else
        Platform::ProgramFail(parser, "invalid operation");
}

/* evaluate an infix operator */
void Expression::ExpressionInfixOperator(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, LexToken op,
    Value *bottomValue, Value *topValue) {
    long resultInt = 0;
    Value *stackValue;
    void *pointer;

#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionInfixOperator()\n");
#endif

    if (bottomValue == NULL || topValue == NULL)
        Platform::ProgramFail(parser, "invalid expression");

    if (op == kTokenLeftSquareBracket) {
        /* array index */
        int ArrayIndex;
        Value *result = NULL;

        if (!IS_NUMERIC_COERCIBLE(topValue))
            Platform::ProgramFail(parser, "array index must be an integer");

        ArrayIndex = ExpressionCoerceInteger(topValue);

        /* make the array element result */
        switch (bottomValue->typ->base) {
        case kTypeArray:
            result = Variable::VariableAllocValueFromExistingData(pc, parser,
            bottomValue->typ->fromType,
            (AnyValue*)(&bottomValue->val->arrayMem[0] +
                Type::TypeSize(bottomValue->typ,
            ArrayIndex, true)),
            bottomValue->isLValue, bottomValue->lValueFrom);
            break;
        case kTypePointer: result = Variable::VariableAllocValueFromExistingData(pc, parser,
            bottomValue->typ->fromType,
            (AnyValue*)((char*)bottomValue->val->pointer +
                Type::TypeSize(bottomValue->typ->fromType,
            0, true) * ArrayIndex),
            bottomValue->isLValue, bottomValue->lValueFrom);
            break;
        default:
            Platform::ProgramFail(parser, "this %t is not an array", bottomValue->typ);
            break;
        }

        ExpressionStackPushValueNode(parser, stackTop, result);
    } else if (op == kTokenQuestionMark) {
        ExpressionQuestionMarkOperator(parser, stackTop, topValue, bottomValue);
    } else if (op == kTokenColon) {
        ExpressionColonOperator(parser, stackTop, topValue, bottomValue);
    } else if ((topValue->typ == &parser->pc->fPType && bottomValue->typ == &parser->pc->fPType) ||
              (topValue->typ == &parser->pc->fPType && IS_NUMERIC_COERCIBLE(bottomValue)) ||
              (IS_NUMERIC_COERCIBLE(topValue) && bottomValue->typ == &parser->pc->fPType)) {
        /* floating point infix arithmetic */
        int resultIsInt = false;
        double resultFP = 0.0;
        double topFP = (topValue->typ == &parser->pc->fPType) ?
            topValue->val->fP : (double)ExpressionCoerceInteger(topValue);
        double bottomFP = (bottomValue->typ == &parser->pc->fPType) ?
            bottomValue->val->fP : (double)ExpressionCoerceInteger(bottomValue);

        switch (op) {
        case kTokenAssign:
            ASSIGN_FP_OR_INT(topFP);
            break;
        case kTokenAddAssign:
            ASSIGN_FP_OR_INT(bottomFP + topFP);
            break;
        case kTokenSubtractAssign:
            ASSIGN_FP_OR_INT(bottomFP - topFP);
            break;
        case kTokenMultiplyAssign:
            ASSIGN_FP_OR_INT(bottomFP * topFP);
            break;
        case kTokenDivideAssign:
            ASSIGN_FP_OR_INT(bottomFP / topFP);
            break;
        case kTokenEqual:
            resultInt = bottomFP == topFP;
            resultIsInt = true;
            break;
        case kTokenNotEqual:
            resultInt = bottomFP != topFP;
            resultIsInt = true;
            break;
        case kTokenLessThan:
            resultInt = bottomFP < topFP;
            resultIsInt = true;
            break;
        case kTokenGreaterThan:
            resultInt = bottomFP > topFP;
            resultIsInt = true;
            break;
        case kTokenLessEqual:
            resultInt = bottomFP <= topFP;
            resultIsInt = true;
            break;
        case kTokenGreaterEqual:
            resultInt = bottomFP >= topFP;
            resultIsInt = true;
            break;
        case kTokenPlus:
            resultFP = bottomFP + topFP;
            break;
        case kTokenMinus:
            resultFP = bottomFP - topFP;
            break;
        case kTokenAsterisk:
            resultFP = bottomFP * topFP;
            break;
        case kTokenSlash:
            resultFP = bottomFP / topFP;
            break;
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }

        if (resultIsInt)
            ExpressionPushInt(parser, stackTop, resultInt);
        else
            ExpressionPushFP(parser, stackTop, resultFP);
    } else if (IS_NUMERIC_COERCIBLE(topValue) && IS_NUMERIC_COERCIBLE(bottomValue)) {
        /* integer operation */
        long topInt = ExpressionCoerceInteger(topValue);
        long bottomInt = ExpressionCoerceInteger(bottomValue);
        switch (op) {
        case kTokenAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue, topInt, false);
            break;
        case kTokenAddAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt + topInt, false);
            break;
        case kTokenSubtractAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt-topInt, false);
            break;
        case kTokenMultiplyAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt*topInt, false);
            break;
        case kTokenDivideAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt/topInt, false);
            break;
        case kTokenModulusAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt%topInt, false);
            break;
        case kTokenShiftLeftAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt<<topInt, false);
            break;
        case kTokenShiftRightAssign:
            //resultInt = ExpressionAssignInt(parser, bottomValue,
            //    bottomInt>>topInt, false);
            if (bottomValue->typ->base == kTypeUnsignedInt || bottomValue->typ->base == kTypeUnsignedLong)
                resultInt = ExpressionAssignInt(parser, bottomValue, (uint64_t) bottomInt >> topInt, false);
            else
                resultInt = ExpressionAssignInt(parser, bottomValue, bottomInt >> topInt, false);
            break;
        case kTokenArithmeticAndAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt&topInt, false);
            break;
        case kTokenArithmeticOrAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt|topInt, false);
            break;
        case kTokenArithmeticExorAssign:
            resultInt = ExpressionAssignInt(parser, bottomValue,
                bottomInt^topInt, false);
            break;
        case kTokenLogicalOr:
            resultInt = bottomInt || topInt;
            break;
        case kTokenLogicalAnd:
            resultInt = bottomInt && topInt;
            break;
        case kTokenArithmeticOr:
            resultInt = bottomInt | topInt;
            break;
        case kTokenArithmeticExor:
            resultInt = bottomInt ^ topInt;
            break;
        case kTokenAmpersand:
            resultInt = bottomInt & topInt;
            break;
        case kTokenEqual:
            resultInt = bottomInt == topInt;
            break;
        case kTokenNotEqual:
            resultInt = bottomInt != topInt;
            break;
        case kTokenLessThan:
            resultInt = bottomInt < topInt;
            break;
        case kTokenGreaterThan:
            resultInt = bottomInt > topInt;
            break;
        case kTokenLessEqual:
            resultInt = bottomInt <= topInt;
            break;
        case kTokenGreaterEqual:
            resultInt = bottomInt >= topInt;
            break;
        case kTokenShiftLeft:
            resultInt = bottomInt << topInt;
            break;
        case kTokenShiftRight:
            resultInt = bottomInt >> topInt;
            break;
        case kTokenPlus:
            resultInt = bottomInt + topInt;
            break;
        case kTokenMinus:
            resultInt = bottomInt - topInt;
            break;
        case kTokenAsterisk:
            resultInt = bottomInt * topInt;
            break;
        case kTokenSlash:
            resultInt = bottomInt / topInt;
            break;
        case kTokenModulus:
            resultInt = bottomInt % topInt;
            break;
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }
        ExpressionPushInt(parser, stackTop, resultInt);
    } else if (bottomValue->typ->base == kTypePointer &&
            IS_NUMERIC_COERCIBLE(topValue)) {
        /* pointer/integer infix arithmetic */
        long topInt = ExpressionCoerceInteger(topValue);

        if (op == kTokenEqual || op == kTokenNotEqual) {
            /* comparison to a NULL pointer */
            if (topInt != 0)
                Platform::ProgramFail(parser, "invalid operation");

            if (op == kTokenEqual)
                ExpressionPushInt(parser, stackTop,
                    bottomValue->val->pointer == NULL);
            else
                ExpressionPushInt(parser, stackTop,
                    bottomValue->val->pointer != NULL);
        } else if (op == kTokenPlus || op == kTokenMinus) {
            /* pointer arithmetic */
            int size = Type::TypeSize(bottomValue->typ->fromType, 0, true);

            pointer = bottomValue->val->pointer;
            if (pointer == NULL)
                Platform::ProgramFail(parser, "c. invalid use of a NULL pointer");

            if (op == kTokenPlus)
                pointer = (void*)((char*)pointer + topInt * size);
            else
                pointer = (void*)((char*)pointer - topInt * size);

            stackValue = ExpressionStackPushValueByType(parser, stackTop,
                bottomValue->typ);
            stackValue->val->pointer = pointer;
        } else if (op == kTokenAssign && topInt == 0) {
            /* assign a NULL pointer */
            Interpreter::HeapUnpopStack(sizeof(Value));
            ExpressionAssign(pc, parser, bottomValue, topValue, false, NULL, 0, false);
            ExpressionStackPushValueNode(parser, stackTop, bottomValue);
        } else if (op == kTokenAddAssign || op == kTokenSubtractAssign) {
            /* pointer arithmetic */
            int size = Type::TypeSize(bottomValue->typ->fromType, 0, true);

            pointer = bottomValue->val->pointer;
            if (pointer == NULL)
                Platform::ProgramFail(parser, "d. invalid use of a NULL pointer");

            if (op == kTokenAddAssign)
                pointer = (void*)((char*)pointer + topInt * size);
            else
                pointer = (void*)((char*)pointer - topInt * size);

            Interpreter::HeapUnpopStack(sizeof(Value));
            bottomValue->val->pointer = pointer;
            ExpressionStackPushValueNode(parser, stackTop, bottomValue);
        } else
            Platform::ProgramFail(parser, "invalid operation");
    } else if (bottomValue->typ->base == kTypePointer &&
            topValue->typ->base == kTypePointer && op != kTokenAssign) {
        /* pointer/pointer operations */
        char *TopLoc = (char*)topValue->val->pointer;
        char *BottomLoc = (char*)bottomValue->val->pointer;

        switch (op) {
        case kTokenEqual:
            ExpressionPushInt(parser, stackTop, BottomLoc == TopLoc);
            break;
        case kTokenNotEqual:
            ExpressionPushInt(parser, stackTop, BottomLoc != TopLoc);
            break;
        case kTokenMinus:
            ExpressionPushInt(parser, stackTop, BottomLoc - TopLoc);
            break;
        default:
            Platform::ProgramFail(parser, "invalid operation");
            break;
        }
    } else if (op == kTokenAssign) {
        /* assign a non-numeric type */
        Interpreter::HeapUnpopStack(sizeof(Value));
        /* XXX - possible bug if lvalue is a temp Value and takes more
            than sizeof(Value) */
        ExpressionAssign(pc, parser, bottomValue, topValue, false, NULL, 0, false);
        ExpressionStackPushValueNode(parser, stackTop, bottomValue);
    } else if (op == kTokenCast) {
        /* cast a Value to a different type */
        /* XXX - possible bug if the destination type takes more than s
            izeof(Value) + sizeof(ValueType *) */
        Value *valueLoc = ExpressionStackPushValueByType(parser, stackTop,
            bottomValue->val->typ);
        ExpressionAssign(pc, parser, valueLoc, topValue, true, NULL, 0, true);
    } else
        Platform::ProgramFail(parser, "invalid operation");
}

/* take the contents of the expression stack and compute the top until
    there's nothing greater than the given precedence */
void Expression::ExpressionStackCollapse(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, int precedence, int *ignorePrecedence) {
    int foundPrecedence = precedence;
    Value *topValue;
    Value *bottomValue;
    ExpressionStack *topStackNode = *stackTop;
    ExpressionStack *topOperatorNode;

#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionStackCollapse(%d):\n", precedence);
    ExpressionStackShow(parser->pc, *stackTop);
#endif
    while (topStackNode != NULL && topStackNode->next != NULL &&
            foundPrecedence >= precedence) {
        /* find the top operator on the stack */
        if (topStackNode->order == kOrderNone)
            topOperatorNode = topStackNode->next;
        else
            topOperatorNode = topStackNode;

        foundPrecedence = topOperatorNode->precedence;

        /* does it have a high enough precedence? */
        if (foundPrecedence >= precedence && topOperatorNode != NULL) {
            /* execute this operator */
            switch (topOperatorNode->order) {
            case kOrderPrefix:
                /* prefix evaluation */
#ifdef DEBUG_EXPRESSIONS
                printf("prefix evaluation\n");
#endif
                topValue = topStackNode->val;

                /* pop the Value and then the prefix operator - assume
                    they'll still be there until we're done */
                Interpreter::HeapPopStack(NULL,
                    sizeof(ExpressionStack) +
                    sizeof(Value) +
                    Type::TypeStackSizeValue(topValue));
                Interpreter::HeapPopStack(topOperatorNode,
                    sizeof(ExpressionStack));
                *stackTop = topOperatorNode->next;

                /* do the prefix operation */
                if (parser->mode == kRunModeRun /* && foundPrecedence < *ignorePrecedence */) {
                    /* run the operator */
                    ExpressionPrefixOperator(pc, parser, stackTop,
                        topOperatorNode->op, topValue);
                } else {
                    /* we're not running it so just return 0 */
                    ExpressionPushInt(parser, stackTop, 0);
                }
                break;
            case kOrderPostfix:
                /* postfix evaluation */
#ifdef DEBUG_EXPRESSIONS
                printf("postfix evaluation\n");
#endif
                topValue = topStackNode->next->val;

                /* pop the postfix operator and then the Value - assume
                    they'll still be there until we're done */
                Interpreter::HeapPopStack(NULL, sizeof(ExpressionStack));
                Interpreter::HeapPopStack(topValue,
                    sizeof(ExpressionStack) +
                    sizeof(Value) +
                    Type::TypeStackSizeValue(topValue));
                *stackTop = topStackNode->next->next;

                /* do the postfix operation */
                if (parser->mode == kRunModeRun /* && foundPrecedence < *ignorePrecedence */) {
                    /* run the operator */
                    ExpressionPostfixOperator(parser, stackTop,
                        topOperatorNode->op, topValue);
                } else {
                    /* we're not running it so just return 0 */
                    ExpressionPushInt(parser, stackTop, 0);
                }
                break;
            case kOrderInfix:
                /* infix evaluation */
#ifdef DEBUG_EXPRESSIONS
                printf("infix evaluation\n");
#endif
                topValue = topStackNode->val;
                if (topValue != NULL) {
                    bottomValue = topOperatorNode->next->val;

                    /* pop a Value, the operator and another Value - assume
                        they'll still be there until we're done */
                    Interpreter::HeapPopStack(NULL,
                        sizeof(ExpressionStack) +
                        sizeof(Value) +
                        Type::TypeStackSizeValue(topValue));
                    Interpreter::HeapPopStack(NULL,
                        sizeof(ExpressionStack));
                    Interpreter::HeapPopStack(bottomValue,
                        sizeof(ExpressionStack) +
                        sizeof(Value) +
                        Type::TypeStackSizeValue(bottomValue));
                    *stackTop = topOperatorNode->next->next;

                    /* do the infix operation */
                    if (parser->mode == kRunModeRun /* && foundPrecedence <= *ignorePrecedence */) {
                        /* run the operator */
                        ExpressionInfixOperator(pc, parser, stackTop,
                            topOperatorNode->op, bottomValue, topValue);
                    } else {
                        /* we're not running it so just return 0 */
                        ExpressionPushInt(parser, stackTop, 0);
                    }
                } else
                    foundPrecedence = -1;
                break;
            case kOrderNone:
            default:
                /* this should never happen */
                assert(topOperatorNode->order != kOrderNone);
                break;
            }

            /* if we've returned above the ignored precedence level
                turn ignoring off */
            if (foundPrecedence <= *ignorePrecedence)
                *ignorePrecedence = DEEP_PRECEDENCE;
        }
#ifdef DEBUG_EXPRESSIONS
        ExpressionStackShow(parser->pc, *stackTop);
#endif
        topStackNode = *stackTop;
    }
#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionStackCollapse() finished\n");
    ExpressionStackShow(parser->pc, *stackTop);
#endif
}

/* push an operator on to the expression stack */
void Expression::ExpressionStackPushOperator(ParseState *parser,
    ExpressionStack **stackTop, OperatorOrder order,
    LexToken token, int precedence) {
    ExpressionStack *stackNode = (ExpressionStack *)(parser->pc, parser,
        sizeof(*stackNode), false);
    stackNode->next = *stackTop;
    stackNode->order = order;
    stackNode->op = token;
    stackNode->precedence = precedence;
    *stackTop = stackNode;
#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionStackPushOperator()\n");
#endif
#ifdef FANCY_ERROR_MESSAGES
    stackNode->line = parser->line;
    stackNode->characterPos = parser->characterPos;
#endif
#ifdef DEBUG_EXPRESSIONS
    ExpressionStackShow(parser->pc, *stackTop);
#endif
}

/* do the '.' and '->' operators */
void Expression::ExpressionGetStructElement(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, LexToken token) {
    Value *ident;

    /* get the identifier following the '.' or '->' */
    if (Lex::LexGetToken(parser, &ident, true) != kTokenIdentifier)
        Platform::ProgramFail(parser, "need an structure or union member after '%s'",
            (token == kTokenDot) ? "." : "->");

    if (parser->mode == kRunModeRun) {
        /* look up the struct element */
        Value *ParamVal = (*stackTop)->val;
        Value *StructVal = ParamVal;
        ValueType *StructType = ParamVal->typ;
        char *derefDataLoc = (char *)ParamVal->val;
        Value *MemberValue = NULL;
        Value *result;

        /* if we're doing '->' dereference the struct pointer first */
        if (token == kTokenArrow)
            derefDataLoc = (char *)Variable::VariableDereferencePointer(ParamVal, &StructVal,
                NULL, &StructType, NULL);

        if (StructType->base != kTypeStruct && StructType->base != kTypeUnion)
            Platform::ProgramFail(parser,
                "can't use '%s' on something that's not a struct or union %s : it's a %t",
                (token == kTokenDot) ? "." : "->",
                (token == kTokenArrow) ? "pointer" : "", ParamVal->typ);

        if (!MyTable::TableGet(StructType->members, ident->val->identifier,
                &MemberValue, NULL, NULL, NULL))
            Platform::ProgramFail(parser, "doesn't have a member called '%s'",
                ident->val->identifier);

        /* pop the Value - assume it'll still be there until we're done */
        Interpreter::HeapPopStack(ParamVal,
            sizeof(ExpressionStack) +
            sizeof(Value) +
            Type::TypeStackSizeValue(StructVal));
        *stackTop = (*stackTop)->next;

        /* make the result Value for this member only */
        result = Variable::VariableAllocValueFromExistingData(pc, parser, MemberValue->typ,
            (AnyValue *)(derefDataLoc + MemberValue->val->integer), true,
            (StructVal != NULL) ? StructVal->lValueFrom : NULL);
        ExpressionStackPushValueNode(parser, stackTop, result);
    }
}

/* parse an expression with operator precedence */
int Expression::ExpressionParse(Interpreter *pc, ParseState *parser, Value **result) {
    int prefixState = true;
    int done = false;
    int bracketPrecedence = 0;
    int localPrecedence;
    int precedence = 0;
    int ignorePrecedence = DEEP_PRECEDENCE;
    int ternaryDepth = 0;
    Value *lexValue;
    ExpressionStack *stackTop = NULL;

#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionParse():\n");
#endif

    do {
        ParseState PreState;
        LexToken token;

        Parse::ParserCopy(&PreState, parser);
        token = Lex::LexGetToken(parser, &lexValue, true);
        if ((((int)token > kTokenComma && (int)token <= (int)kTokenOpenBracket) ||
               (token == kTokenCloseBracket && bracketPrecedence != 0)) &&
               (token != kTokenColon || ternaryDepth > 0)) {
            /* it's an operator with precedence */
            if (prefixState) {
                /* expect a prefix operator */
                if (operatorPrecedence[(int)token].prefixPrecedence == 0)
                    Platform::ProgramFail(parser, "operator not expected here");

                localPrecedence = operatorPrecedence[(int)token].prefixPrecedence;
                precedence = bracketPrecedence + localPrecedence;

                if (token == kTokenOpenBracket) {
                    /* it's either a new bracket level or a cast */
                    LexToken BracketToken = Lex::LexGetToken(parser, &lexValue, false);
                    if (IsTypeToken(parser, BracketToken, lexValue) &&
                            (stackTop == NULL || stackTop->op != kTokenSizeof)) {
                        /* it's a cast - get the new type */
                        ValueType *CastType;
                        char *CastIdentifier;
                        Value *CastTypeValue;

                        Type::TypeParse(pc, parser, &CastType, &CastIdentifier, NULL);
                        if (Lex::LexGetToken(parser, &lexValue, true) != kTokenCloseBracket)
                            Platform::ProgramFail(parser, "brackets not closed");

                        /* scan and collapse the stack to the precedence of
                            this infix cast operator, then push */
                        precedence = bracketPrecedence +
                            operatorPrecedence[(int)kTokenCast].prefixPrecedence;

                        ExpressionStackCollapse(pc, parser, &stackTop, precedence+1,
                            &ignorePrecedence);
                        CastTypeValue = (parser->pc,
                            parser, &parser->pc->typeType, false, NULL, false);
                        CastTypeValue->val->typ = CastType;
                        ExpressionStackPushValueNode(parser, &stackTop, CastTypeValue);
                        ExpressionStackPushOperator(parser, &stackTop, kOrderInfix,
                            kTokenCast, precedence);
                    } else {
                        /* boost the bracket operator precedence */
                        bracketPrecedence += BRACKET_PRECEDENCE;
                    }
                } else {
                    /* scan and collapse the stack to the precedence of
                        this operator, then push */

                    /* take some extra care for double prefix operators,
                        e.g. x = - -5, or x = **y */
                    int NextToken = Lex::LexGetToken(parser, NULL, false);
                    int TempPrecedenceBoost = 0;
                    if (NextToken > kTokenComma && NextToken < kTokenOpenBracket) {
                        int NextPrecedence =
                            operatorPrecedence[(int)NextToken].prefixPrecedence;

                        /* two prefix operators with equal precedence? make
                            sure the innermost one runs first */
                        /* XXX - probably not correct, but can't find a
                            test that fails at this */
                        if (localPrecedence == NextPrecedence)
                            TempPrecedenceBoost = -1;
                    }

                    ExpressionStackCollapse(pc, parser, &stackTop, precedence,
                        &ignorePrecedence);
                    ExpressionStackPushOperator(parser, &stackTop, kOrderPrefix,
                        token, precedence + TempPrecedenceBoost);
                }
            } else {
                /* expect an infix or postfix operator */
                if (operatorPrecedence[(int)token].postfixPrecedence != 0) {
                    switch (token) {
                    case kTokenCloseBracket:
                    case kTokenRightSquareBracket:
                        if (bracketPrecedence == 0) {
                            /* assume this bracket is after the end of the
                                expression */
                            Parse::ParserCopy(parser, &PreState);
                            done = true;
                        } else {
                            /* collapse to the bracket precedence */
                            ExpressionStackCollapse(pc, parser, &stackTop,
                                bracketPrecedence, &ignorePrecedence);
                            bracketPrecedence -= BRACKET_PRECEDENCE;
                        }
                        break;
                    default:
                        /* scan and collapse the stack to the precedence of
                            this operator, then push */
                        precedence = bracketPrecedence +
                            operatorPrecedence[(int)token].postfixPrecedence;
                        ExpressionStackCollapse(pc, parser, &stackTop, precedence,
                            &ignorePrecedence);
                        ExpressionStackPushOperator(parser, &stackTop,
                            kOrderPostfix, token, precedence);
                        break;
                    }
                } else if (operatorPrecedence[(int)token].infixPrecedence != 0) {
                    /* scan and collapse the stack, then push */
                    precedence = bracketPrecedence +
                        operatorPrecedence[(int)token].infixPrecedence;

                    /* for right to left order, only go down to the next
                        higher precedence so we evaluate it in reverse order */
                    /* for left to right order, collapse down to this precedence
                        so we evaluate it in forward order */
                    if (IS_LEFT_TO_RIGHT(operatorPrecedence[(int)token].infixPrecedence))
                        ExpressionStackCollapse(pc, parser, &stackTop, precedence,
                            &ignorePrecedence);
                    else
                        ExpressionStackCollapse(pc, parser, &stackTop, precedence+1,
                            &ignorePrecedence);

                    if (token == kTokenDot || token == kTokenArrow) {
                        /* this operator is followed by a struct element so
                            handle it as a special case */
                        ExpressionGetStructElement(pc, parser, &stackTop, token);
                    } else {
                        /* if it's a && or || operator we may not need to
                            evaluate the right hand side of the expression */
                        if ((token == kTokenLogicalOr || token == kTokenLogicalAnd) &&
                                IS_NUMERIC_COERCIBLE(stackTop->val)) {
                            long LHSInt = ExpressionCoerceInteger(stackTop->val);
                            if (((token == kTokenLogicalOr && LHSInt) ||
                                    (token == kTokenLogicalAnd && !LHSInt)) &&
                                 (ignorePrecedence > precedence) )
                                ignorePrecedence = precedence;
                        }

                        /* push the operator on the stack */
                        ExpressionStackPushOperator(parser, &stackTop,
                            kOrderInfix, token, precedence);
                        prefixState = true;

                        switch (token) {
                        case kTokenQuestionMark:
                            ternaryDepth++;
                            break;
                        case kTokenColon:
                            ternaryDepth--;
                            break;
                        default:
                            break;
                        }
                    }

                    /* treat an open square bracket as an infix array index
                        operator followed by an open bracket */
                    if (token == kTokenLeftSquareBracket) {
                        /* boost the bracket operator precedence, then push */
                        bracketPrecedence += BRACKET_PRECEDENCE;
                    }
                } else
                    Platform::ProgramFail(parser, "operator not expected here");
            }
        } else if (token == kTokenIdentifier) {
            /* it's a variable, function or a macro */
            if (!prefixState)
                Platform::ProgramFail(parser, "identifier not expected here");

            if (Lex::LexGetToken(parser, NULL, false) == kTokenOpenBracket) {
                ExpressionParseFunctionCall(pc, parser, &stackTop,
                    lexValue->val->identifier,
                    parser->mode == kRunModeRun && precedence < ignorePrecedence);
            } else {
                if (parser->mode == kRunModeRun /* && precedence < ignorePrecedence */) {
                    Value *VariableValue = NULL;

                    (parser->pc, parser, lexValue->val->identifier,
                        &VariableValue);
                    if (VariableValue->typ->base == kTypeMacro) {
                        /* evaluate a macro as a kind of simple subroutine */
                        ParseState MacroParser;
                        Value *MacroResult;

                        Parse::ParserCopy(&MacroParser, &VariableValue->val->MacroDef.body);
                        MacroParser.mode = parser->mode;
                        if (VariableValue->val->MacroDef.numParams != 0)
                            Platform::ProgramFail(&MacroParser, "macro arguments missing");

                        if (!ExpressionParse(pc, &MacroParser, &MacroResult) ||
                                Lex::LexGetToken(&MacroParser, NULL, false) !=
                                    kTokenEndOfFunction)
                            Platform::ProgramFail(&MacroParser, "expression expected");

                        ExpressionStackPushValueNode(parser, &stackTop, MacroResult);
                    } else if (VariableValue->typ == &parser->pc->voidType)
                        Platform::ProgramFail(parser, "a void Value isn't much use here");
                    else
                        ExpressionStackPushLValue(pc, parser, &stackTop,
                        VariableValue, 0); /* it's a Value variable */
                } else /* push a dummy Value */
                    ExpressionPushInt(parser, &stackTop, 0);

            }

             /* if we've successfully ignored the RHS turn ignoring off */
            if (precedence <= ignorePrecedence)
                ignorePrecedence = DEEP_PRECEDENCE;

            prefixState = false;
        } else if ((int)token > kTokenCloseBracket &&
                                        (int)token <= kTokenCharacterConstant) {
            /* it's a Value of some sort, push it */
            if (!prefixState)
                Platform::ProgramFail(parser, "Value not expected here");

            prefixState = false;
            ExpressionStackPushValue(parser, &stackTop, lexValue);
        } else if (IsTypeToken(parser, token, lexValue)) {
            /* it's a type. push it on the stack like a Value.
                this is used in sizeof() */
            ValueType *typ;
            char *identifier;
            Value *TypeValue;

            if (!prefixState)
                Platform::ProgramFail(parser, "type not expected here");

            prefixState = false;
            Parse::ParserCopy(parser, &PreState);
            Type::TypeParse(pc, parser, &typ, &identifier, NULL);
            TypeValue = (parser->pc, parser,
                &parser->pc->typeType, false, NULL, false);
            TypeValue->val->typ = typ;
            ExpressionStackPushValueNode(parser, &stackTop, TypeValue);
        } else {
            /* it isn't a token from an expression */
            Parse::ParserCopy(parser, &PreState);
            done = true;
        }
    } while (!done);

    /* check that brackets have been closed */
    if (bracketPrecedence > 0)
        Platform::ProgramFail(parser, "brackets not closed");

    /* scan and collapse the stack to precedence 0 */
    ExpressionStackCollapse(pc, parser, &stackTop, 0, &ignorePrecedence);

    /* fix up the stack and return the result if we're in run mode */
    if (stackTop != NULL) {
        /* all that should be left is a single Value on the stack */
        if (parser->mode == kRunModeRun) {
            if (stackTop->order != kOrderNone || stackTop->next != NULL)
                Platform::ProgramFail(parser, "invalid expression");

            *result = stackTop->val;
            Interpreter::HeapPopStack(stackTop, sizeof(ExpressionStack));
        } else
            Interpreter::HeapPopStack(stackTop->val,
                sizeof(ExpressionStack) +
                sizeof(Value) +
                Type::TypeStackSizeValue(stackTop->val));
    }

#ifdef DEBUG_EXPRESSIONS
    printf("ExpressionParse() done\n\n");
    ExpressionStackShow(parser->pc, stackTop);
#endif
    return stackTop != NULL;
}

/* do a parameterized macro call */
void Expression::ExpressionParseMacroCall(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, const char *macroName,
    MacroDef *mDef) {
    int argCount;
    LexToken token;
    Value *returnValue = NULL;
    Value *param;
    Value **ParamArray = NULL;

    if (parser->mode == kRunModeRun) {
        /* create a stack frame for this macro */
        /* largest return type there is */
        ExpressionStackPushValueByType(parser, stackTop, &parser->pc->fPType);
        returnValue = (*stackTop)->val;
        Interpreter::HeapPushStackFrame();
        ParamArray = (Value **)Interpreter::HeapAllocStack(sizeof(Value*)*mDef->numParams);
        if (ParamArray == NULL)
            Platform::ProgramFail(parser, "(ExpressionParseMacroCall) out of memory");
    } else
        ExpressionPushInt(parser, stackTop, 0);

    /* parse arguments */
    argCount = 0;
    do {
        if (ExpressionParse(pc, parser, &param)) {
            if (parser->mode == kRunModeRun) {
                if (argCount < mDef->numParams)
                    ParamArray[argCount] = param;
                else
                    Platform::ProgramFail(parser, "too many arguments to %s()", macroName);
            }

            argCount++;
            token = Lex::LexGetToken(parser, NULL, true);
            if (token != kTokenComma && token != kTokenCloseBracket)
                Platform::ProgramFail(parser, "comma expected");
        } else {
            /* end of argument list? */
            token = Lex::LexGetToken(parser, NULL, true);
            if (token != kTokenCloseBracket)
                Platform::ProgramFail(parser, "bad argument");
        }

    } while (token != kTokenCloseBracket);

    if (parser->mode == kRunModeRun) {
        /* evaluate the macro */
        ParseState MacroParser;
        int Count;
        Value *EvalValue;

        if (argCount < mDef->numParams)
            Platform::ProgramFail(parser, "not enough arguments to '%s'", macroName);

        if (mDef->body.pos == NULL)
            Platform::ProgramFail(parser,
                "ExpressionParseMacroCall macroName: '%s' is undefined",
                macroName);

        Parse::ParserCopy(&MacroParser, &mDef->body);
        MacroParser.mode = parser->mode;
        Variable::VariableStackFrameAdd(parser, macroName, 0);
        parser->pc->topStackFrame->numParams = argCount;
        parser->pc->topStackFrame->returnValue = returnValue;
        for (Count = 0; Count < mDef->numParams; Count++)
            (parser->pc, parser, mDef->paramName[Count],
                ParamArray[Count], NULL, true);

        ExpressionParse(pc, &MacroParser, &EvalValue);
        ExpressionAssign(pc, parser, returnValue, EvalValue, true, macroName, 0, false);
        Variable::VariableStackFramePop(parser);
        Interpreter::HeapPopStackFrame();
    }
}

/* do a function call */
void Expression::ExpressionParseFunctionCall(Interpreter *pc, ParseState *parser,
    ExpressionStack **stackTop, const char *funcName, int runIt) {
    int argCount;
    LexToken token = Lex::LexGetToken(parser, NULL, true);    /* open bracket */
    RunMode oldMode = parser->mode;
    Value *returnValue = NULL;
    Value *funcValue = NULL;
    Value *param;
    Value **ParamArray = NULL;

    if (runIt) {
        /* get the function definition */
        (parser->pc, parser, funcName, &funcValue);

        if (funcValue->typ->base == kTypeMacro) {
            /* this is actually a macro, not a function */
            ExpressionParseMacroCall(pc, parser, stackTop, funcName,
                &funcValue->val->MacroDef);
            return;
        }

        if (funcValue->typ->base != kTypeFunction)
            Platform::ProgramFail(parser, "%t is not a function - can't call",
                funcValue->typ);

        ExpressionStackPushValueByType(parser, stackTop,
            funcValue->val->FuncDef.returnType);
        returnValue = (*stackTop)->val;
        Interpreter::HeapPushStackFrame();
        ParamArray = (Value **)Interpreter::HeapAllocStack(sizeof(Value*)*funcValue->val->FuncDef.numParams);
        if (ParamArray == NULL)
            Platform::ProgramFail(parser, "(ExpressionParseFunctionCall) out of memory");
    } else {
        ExpressionPushInt(parser, stackTop, 0);
        parser->mode = kRunModeSkip;
    }

    /* parse arguments */
    argCount = 0;
    do {
        if (runIt && argCount < funcValue->val->FuncDef.numParams)
            ParamArray[argCount] = (parser->pc, parser,
                funcValue->val->FuncDef.paramType[argCount], false, NULL, false);

        if (ExpressionParse(pc, parser, &param)) {
            if (runIt) {
                if (argCount < funcValue->val->FuncDef.numParams) {
                    ExpressionAssign(pc, parser, ParamArray[argCount], param, true,
                        funcName, argCount+1, false);
                    Variable::VariableStackPop(parser, param);
                } else {
                    if (!funcValue->val->FuncDef.varArgs)
                        Platform::ProgramFail(parser, "too many arguments to %s()", funcName);
                }
            }

            argCount++;
            token = Lex::LexGetToken(parser, NULL, true);
            if (token != kTokenComma && token != kTokenCloseBracket)
                Platform::ProgramFail(parser, "comma expected");
        } else {
            /* end of argument list? */
            token = Lex::LexGetToken(parser, NULL, true);
            if (token != kTokenCloseBracket)
                Platform::ProgramFail(parser, "bad argument");
        }

    } while (token != kTokenCloseBracket);

    if (runIt) {
        /* run the function */
        if (argCount < funcValue->val->FuncDef.numParams)
            Platform::ProgramFail(parser, "not enough arguments to '%s'", funcName);

        if (funcValue->val->FuncDef.intrinsic == NULL) {
            /* run a user-defined function */
            int Count;
            int OldScopeID = parser->scopeID;
            ParseState FuncParser;

            if (funcValue->val->FuncDef.body.pos == NULL)
                Platform::ProgramFail(parser,
                    "ExpressionParseFunctionCall funcName: '%s' is undefined",
                    funcName);

            Parse::ParserCopy(&FuncParser, &funcValue->val->FuncDef.body);
            Variable::VariableStackFrameAdd(parser, funcName,
                funcValue->val->FuncDef.intrinsic ? funcValue->val->FuncDef.numParams : 0);
            parser->pc->topStackFrame->numParams = argCount;
            parser->pc->topStackFrame->returnValue = returnValue;

            /* Function parameters should not go out of scope */
            parser->scopeID = -1;

            for (Count = 0; Count < funcValue->val->FuncDef.numParams; Count++)
                (parser->pc, parser,
                    funcValue->val->FuncDef.paramName[Count], ParamArray[Count],
                    NULL, true);

            parser->scopeID = OldScopeID;

            if (Parse::ParseStatement(pc, &FuncParser, true) != kParseResultOk)
                Platform::ProgramFail(&FuncParser, "function body expected");

            if (runIt) {
                if (FuncParser.mode == kRunModeRun &&
                        funcValue->val->FuncDef.returnType != &parser->pc->voidType)
                    Platform::ProgramFail(&FuncParser,
                        "no Value returned from a function returning %t",
                        funcValue->val->FuncDef.returnType);

                else if (FuncParser.mode == kRunModeGoto)
                    Platform::ProgramFail(&FuncParser, "couldn't find goto label '%s'",
                        FuncParser.searchGotoLabel);
            }

            Variable::VariableStackFramePop(parser);
        } else {
            funcValue->val->FuncDef.intrinsic(parser, returnValue, ParamArray,
                                              argCount);
        }

        Interpreter::HeapPopStackFrame();
    }

    parser->mode = oldMode;
}

/* parse an expression */
long Expression::ExpressionParseInt(Interpreter *pc, ParseState *parser) {
    long result = 0;
    Value *val;

    if (!ExpressionParse(pc, parser, &val))
        Platform::ProgramFail(parser, "expression expected");

    if (parser->mode == kRunModeRun) {
        if (!IS_NUMERIC_COERCIBLE_PLUS_POINTERS(val, true))
            Platform::ProgramFail(parser, "integer Value expected instead of %t", val->typ);

        result = ExpressionCoerceInteger(val);
        Variable::VariableStackPop(parser, val);
    }

    return result;
}

